/**************************************************************
 *   File:	Matrix44.h
 * Author:	Andrew Thorpe
 *  Brief:	Full-featured 4x4 matrix class
 **************************************************************/
#include "StdAfx.h"
#include "Matrix44.h"
#include "Vector4.h"

#include <math.h>

using namespace Fossil;
Matrix44& Matrix44::operator= (const Matrix44& rhs)
{
	m_m00 = rhs.m_m00;
	m_m01 = rhs.m_m01;
	m_m02 = rhs.m_m02; 
	m_m03 = rhs.m_m03; 

	m_m10 = rhs.m_m10;
	m_m11 = rhs.m_m11;
	m_m12 = rhs.m_m12;
	m_m13 = rhs.m_m13;

	m_m20 = rhs.m_m20;
	m_m21 = rhs.m_m21;
	m_m22 = rhs.m_m22;
	m_m23 = rhs.m_m23;

	m_m30 = rhs.m_m30; 
	m_m31 = rhs.m_m31; 
	m_m32 = rhs.m_m32; 
	m_m33 = rhs.m_m33;
	return *this;
}


Matrix44 Matrix44::operator* (float rhs) const
{
	return Matrix44(m_m00 * rhs, m_m01 * rhs, m_m02 * rhs, m_m03 * rhs,
					m_m10 * rhs, m_m11 * rhs, m_m12 * rhs, m_m13 * rhs,
					m_m20 * rhs, m_m21 * rhs, m_m22 * rhs, m_m23 * rhs,
					m_m30 * rhs, m_m31 * rhs, m_m32 * rhs, m_m33 * rhs);
}


void Matrix44::operator*=(float rhs)
{
	m_m00 *= rhs;
	m_m01 *= rhs;
	m_m02 *= rhs;
	m_m03 *= rhs;

	m_m10 *= rhs;
	m_m11 *= rhs;
	m_m12 *= rhs;
	m_m13 *= rhs;

	m_m20 *= rhs;
	m_m21 *= rhs;
	m_m22 *= rhs;
	m_m23 *= rhs;

	m_m30 *= rhs;
	m_m31 *= rhs;
	m_m32 *= rhs;
	m_m33 *= rhs;
}

Vector4	Matrix44::operator* (const Fossil::Vector4& rhs) const
{
	return Vector4( ( m_m00 * rhs.m_x ) + ( m_m01 * rhs.m_y ) + ( m_m02 * rhs.m_z ) + ( m_m03 * rhs.m_w ),
					( m_m10 * rhs.m_x ) + ( m_m11 * rhs.m_y ) + ( m_m12 * rhs.m_z ) + ( m_m13 * rhs.m_w ),
					( m_m20 * rhs.m_x ) + ( m_m21 * rhs.m_y ) + ( m_m22 * rhs.m_z ) + ( m_m23 * rhs.m_w ),
					( m_m30 * rhs.m_x ) + ( m_m31 * rhs.m_y ) + ( m_m32 * rhs.m_z ) + ( m_m33 * rhs.m_w ) );
}

Matrix44 Matrix44::operator* (const Matrix44& rhs) const
{
	return Matrix44(( m_m00 * rhs.m_m00 ) + ( m_m01 * rhs.m_m10 ) + ( m_m02 * rhs.m_m20 ) + ( m_m03 * rhs.m_m30 ), 
					( m_m00 * rhs.m_m01 ) + ( m_m01 * rhs.m_m11 ) + ( m_m02 * rhs.m_m21 ) + ( m_m03 * rhs.m_m31 ), 
					( m_m00 * rhs.m_m02 ) + ( m_m01 * rhs.m_m12 ) + ( m_m02 * rhs.m_m22 ) + ( m_m03 * rhs.m_m32 ), 
					( m_m00 * rhs.m_m03 ) + ( m_m01 * rhs.m_m13 ) + ( m_m02 * rhs.m_m23 ) + ( m_m03 * rhs.m_m33 ),

					( m_m10 * rhs.m_m00 ) + ( m_m11 * rhs.m_m10 ) + ( m_m12 * rhs.m_m20 ) + ( m_m13 * rhs.m_m30 ), 
					( m_m10 * rhs.m_m01 ) + ( m_m11 * rhs.m_m11 ) + ( m_m12 * rhs.m_m21 ) + ( m_m13 * rhs.m_m31 ), 
					( m_m10 * rhs.m_m02 ) + ( m_m11 * rhs.m_m12 ) + ( m_m12 * rhs.m_m22 ) + ( m_m13 * rhs.m_m32 ), 
					( m_m10 * rhs.m_m03 ) + ( m_m11 * rhs.m_m13 ) + ( m_m12 * rhs.m_m23 ) + ( m_m13 * rhs.m_m33 ),
					
					( m_m20 * rhs.m_m00 ) + ( m_m21 * rhs.m_m10 ) + ( m_m22 * rhs.m_m20 ) + ( m_m23 * rhs.m_m30 ), 
					( m_m20 * rhs.m_m01 ) + ( m_m21 * rhs.m_m11 ) + ( m_m22 * rhs.m_m21 ) + ( m_m23 * rhs.m_m31 ), 
					( m_m20 * rhs.m_m02 ) + ( m_m21 * rhs.m_m12 ) + ( m_m22 * rhs.m_m22 ) + ( m_m23 * rhs.m_m32 ), 
					( m_m20 * rhs.m_m03 ) + ( m_m21 * rhs.m_m13 ) + ( m_m22 * rhs.m_m23 ) + ( m_m23 * rhs.m_m33 ),

					( m_m30 * rhs.m_m00 ) + ( m_m31 * rhs.m_m10 ) + ( m_m32 * rhs.m_m20 ) + ( m_m33 * rhs.m_m30 ), 
					( m_m30 * rhs.m_m01 ) + ( m_m31 * rhs.m_m11 ) + ( m_m32 * rhs.m_m21 ) + ( m_m33 * rhs.m_m31 ), 
					( m_m30 * rhs.m_m02 ) + ( m_m31 * rhs.m_m12 ) + ( m_m32 * rhs.m_m22 ) + ( m_m33 * rhs.m_m32 ), 
					( m_m30 * rhs.m_m03 ) + ( m_m31 * rhs.m_m13 ) + ( m_m32 * rhs.m_m23 ) + ( m_m33 * rhs.m_m33 ));
}

void Matrix44::operator*=(const Matrix44& rhs)
{
	*this = *this * rhs;
}

Matrix44 Matrix44::operator+ (const Matrix44& rhs) const
{
	return Matrix44(m_m00 + rhs.m_m00, m_m01 + rhs.m_m01, m_m02 + rhs.m_m02, m_m03 + rhs.m_m03,
					m_m10 + rhs.m_m10, m_m11 + rhs.m_m11, m_m12 + rhs.m_m12, m_m13 + rhs.m_m13,
					m_m20 + rhs.m_m20, m_m21 + rhs.m_m21, m_m22 + rhs.m_m22, m_m23 + rhs.m_m23,
					m_m30 + rhs.m_m30, m_m31 + rhs.m_m31, m_m32 + rhs.m_m32, m_m33 + rhs.m_m33);
}

void Matrix44::operator+=(const Matrix44& rhs)
{
	*this = *this + rhs;
}

Matrix44 Matrix44::operator- (const Matrix44& rhs) const
{
	return Matrix44(m_m00 - rhs.m_m00, m_m01 - rhs.m_m01, m_m02 - rhs.m_m02, m_m03 - rhs.m_m03,
					m_m10 - rhs.m_m10, m_m11 - rhs.m_m11, m_m12 - rhs.m_m12, m_m13 - rhs.m_m13,
					m_m20 - rhs.m_m20, m_m21 - rhs.m_m21, m_m22 - rhs.m_m22, m_m23 - rhs.m_m23,
					m_m30 - rhs.m_m30, m_m31 - rhs.m_m31, m_m32 - rhs.m_m32, m_m33 - rhs.m_m33);
}

void Matrix44::operator-=(const Matrix44& rhs)
{
	*this = *this - rhs;
}

Matrix44 Matrix44::Transpose() const
{
	return Matrix44(m_m00, m_m10, m_m20, m_m30,
					m_m01, m_m11, m_m21, m_m31,
					m_m02, m_m12, m_m22, m_m32,
					m_m03, m_m13, m_m23, m_m33);
}

float Matrix44::Determinant() const
{
	return
		m_m03 * m_m12 * m_m21 * m_m30 - m_m02 * m_m13 * m_m21 * m_m30 - m_m03 * m_m11 * m_m22 * m_m30 + m_m01 * m_m13 * m_m22 * m_m30 +
		m_m02 * m_m11 * m_m23 * m_m30 - m_m01 * m_m12 * m_m23 * m_m30 - m_m03 * m_m12 * m_m20 * m_m31 + m_m02 * m_m13 * m_m20 * m_m31 +
		m_m03 * m_m10 * m_m22 * m_m31 - m_m00 * m_m13 * m_m22 * m_m31 - m_m02 * m_m10 * m_m23 * m_m31 + m_m00 * m_m12 * m_m23 * m_m31 +
		m_m03 * m_m11 * m_m20 * m_m32 - m_m01 * m_m13 * m_m20 * m_m32 - m_m03 * m_m10 * m_m21 * m_m32 + m_m00 * m_m13 * m_m21 * m_m32 +
		m_m01 * m_m10 * m_m23 * m_m32 - m_m00 * m_m11 * m_m23 * m_m32 - m_m02 * m_m11 * m_m20 * m_m33 + m_m01 * m_m12 * m_m20 * m_m33 +
		m_m02 * m_m10 * m_m21 * m_m33 - m_m00 * m_m12 * m_m21 * m_m33 - m_m01 * m_m10 * m_m22 * m_m33 + m_m00 * m_m11 * m_m22 * m_m33;
}

Matrix44 Matrix44::Inverse() const
{
	return 
	Matrix44 (	m_m12 * m_m23 * m_m31 - m_m13 * m_m22 * m_m31 + m_m13 * m_m21 * m_m32 - m_m11 * m_m23 * m_m32 - m_m12 * m_m21 * m_m33 + m_m11 * m_m22 * m_m33,
				m_m03 * m_m22 * m_m31 - m_m02 * m_m23 * m_m31 - m_m03 * m_m21 * m_m32 + m_m01 * m_m23 * m_m32 + m_m02 * m_m21 * m_m33 - m_m01 * m_m22 * m_m33,
				m_m02 * m_m13 * m_m31 - m_m03 * m_m12 * m_m31 + m_m03 * m_m11 * m_m32 - m_m01 * m_m13 * m_m32 - m_m02 * m_m11 * m_m33 + m_m01 * m_m12 * m_m33,
				m_m03 * m_m12 * m_m21 - m_m02 * m_m13 * m_m21 - m_m03 * m_m11 * m_m22 + m_m01 * m_m13 * m_m22 + m_m02 * m_m11 * m_m23 - m_m01 * m_m12 * m_m23,
						
				m_m13 * m_m22 * m_m30 - m_m12 * m_m23 * m_m30 - m_m13 * m_m20 * m_m32 + m_m10 * m_m23 * m_m32 + m_m12 * m_m20 * m_m33 - m_m10 * m_m22 * m_m33,
				m_m02 * m_m23 * m_m30 - m_m03 * m_m22 * m_m30 + m_m03 * m_m20 * m_m32 - m_m00 * m_m23 * m_m32 - m_m02 * m_m20 * m_m33 + m_m00 * m_m22 * m_m33,
				m_m03 * m_m12 * m_m30 - m_m02 * m_m13 * m_m30 - m_m03 * m_m10 * m_m32 + m_m00 * m_m13 * m_m32 + m_m02 * m_m10 * m_m33 - m_m00 * m_m12 * m_m33,
				m_m02 * m_m13 * m_m20 - m_m03 * m_m12 * m_m20 + m_m03 * m_m10 * m_m22 - m_m00 * m_m13 * m_m22 - m_m02 * m_m10 * m_m23 + m_m00 * m_m12 * m_m23,
						
				m_m11 * m_m23 * m_m30 - m_m13 * m_m21 * m_m30 + m_m13 * m_m20 * m_m31 - m_m10 * m_m23 * m_m31 - m_m11 * m_m20 * m_m33 + m_m10 * m_m21 * m_m33,
				m_m03 * m_m21 * m_m30 - m_m01 * m_m23 * m_m30 - m_m03 * m_m20 * m_m31 + m_m00 * m_m23 * m_m31 + m_m01 * m_m20 * m_m33 - m_m00 * m_m21 * m_m33,
				m_m01 * m_m13 * m_m30 - m_m03 * m_m11 * m_m30 + m_m03 * m_m10 * m_m31 - m_m00 * m_m13 * m_m31 - m_m01 * m_m10 * m_m33 + m_m00 * m_m11 * m_m33,
				m_m03 * m_m11 * m_m20 - m_m01 * m_m13 * m_m20 - m_m03 * m_m10 * m_m21 + m_m00 * m_m13 * m_m21 + m_m01 * m_m10 * m_m23 - m_m00 * m_m11 * m_m23,
					
				m_m12 * m_m21 * m_m30 - m_m11 * m_m22 * m_m30 - m_m12 * m_m20 * m_m31 + m_m10 * m_m22 * m_m31 + m_m11 * m_m20 * m_m32 - m_m10 * m_m21 * m_m32,
				m_m01 * m_m22 * m_m30 - m_m02 * m_m21 * m_m30 + m_m02 * m_m20 * m_m31 - m_m00 * m_m22 * m_m31 - m_m01 * m_m20 * m_m32 + m_m00 * m_m21 * m_m32,
				m_m02 * m_m11 * m_m30 - m_m01 * m_m12 * m_m30 - m_m02 * m_m10 * m_m31 + m_m00 * m_m12 * m_m31 + m_m01 * m_m10 * m_m32 - m_m00 * m_m11 * m_m32,
				m_m01 * m_m12 * m_m20 - m_m02 * m_m11 * m_m20 + m_m02 * m_m10 * m_m21 - m_m00 * m_m12 * m_m21 - m_m01 * m_m10 * m_m22 + m_m00 * m_m11 * m_m22 )
				
				* (1/Determinant());
}

Matrix44 Matrix44::Zero()
{
	return Matrix44(0.0f, 0.0f, 0.0f, 0.0f,
					0.0f, 0.0f, 0.0f, 0.0f,
					0.0f, 0.0f, 0.0f, 0.0f,
					0.0f, 0.0f, 0.0f, 0.0f);
}

Matrix44 Matrix44::Identity()
{
	return Matrix44(1.0f, 0.0f, 0.0f, 0.0f,
					0.0f, 1.0f, 0.0f, 0.0f,
					0.0f, 0.0f, 1.0f, 0.0f,
					0.0f, 0.0f, 0.0f, 1.0f);
}

Matrix44 Matrix44::Translation(float x, float y, float z)
{
	return Matrix44(1.0f, 0.0f, 0.0f, x,
					0.0f, 1.0f, 0.0f, y,
					0.0f, 0.0f, 1.0f, z,
					0.0f, 0.0f, 0.0f, 1.0f);
}

Matrix44 Matrix44::Scale(float x, float y, float z)
{
	return Matrix44(   x, 0.0f, 0.0f, 0.0f,
					0.0f,    y, 0.0f, 0.0f,
					0.0f, 0.0f,    z, 0.0f,
					0.0f, 0.0f, 0.0f, 1.0f);
}

Matrix44 Matrix44::XRotation(float rad)
{
	float cosR = cos(rad);
	float sinR = sin(rad);
	return Matrix44(1.0f, 0.0f, 0.0f, 0.0f,
					0.0f, cosR, sinR, 0.0f,
					0.0f, -sinR, cosR, 0.0f,
					0.0f, 0.0f, 0.0f, 1.0f);
}

Matrix44 Matrix44::YRotation(float rad)
{
	float cosR = cos(rad);
	float sinR = sin(rad);
	return Matrix44(cosR, 0.0f, -sinR, 0.0f,
					0.0f, 1.0f, 0.0f, 0.0f,
					sinR, 0.0f, cosR, 0.0f,
					0.0f, 0.0f, 0.0f, 1.0f);
}

Matrix44 Matrix44::ZRotation(float rad)
{
	float cosR = cos(rad);
	float sinR = sin(rad);
	return Matrix44(cosR, sinR, 0.0f, 0.0f,
					-sinR, cosR, 0.0f, 0.0f,
					0.0f, 0.0f, 1.0f, 0.0f,
					0.0f, 0.0f, 0.0f, 1.0f);
}
